#pragma once

#include <iostream>
#include <vector>
#include <string>
#include "ProcessDate.hpp"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "task.hpp"

class ProcessPool
{
    const static int defaultnum = 5;

public:
    ProcessPool(int num = defaultnum):procNum(num) {} 
    ~ProcessPool() {}

private:
    void worker(int i)
    {
        while (true)
        {
            int taskId;
            int n = read(0, &taskId, 4);
            if (n == 0)
            {
                break;
            }
            std::cout << "process_" + std::to_string(i) << " 获取一个任务, taskId:" << taskId;
            std::cout << " ,执行任务: ";
            //执行任务
            task[taskId]();
        }
    }

public:
    void start()
    {
        // 用于关闭继承子父进程对于管道的写端
        std::vector<int> closefds;

        // 创建子进程
        for (int i = 1; i <= procNum; i++)
        {
            // 创建管道
            int p[2] = {0};
            int ret = pipe(p);
            if (ret < 0)
            {
                // 管道创建失败
                std::cerr << "PIPE ERROR" << std::endl;
                continue;
            }

            // 添加父进程对于管道的写端，解决子进程释放问题
            closefds.push_back(p[1]);

            pid_t pid = fork();
            if (pid == 0)
            {
                // 子进程关闭写端
                close(p[1]);

                // 对读段进行重定向，方便我们后续获取任务
                dup2(p[0], 0);

                // 关闭继承自父进程对于之前的管道的写端
                if (i > 1)
                {
                    for (auto fd : closefds)
                    {
                        close(fd);
                    }
                }

                // 子进程获取任务，并执行
                worker(i);

                // 当写端关闭，子进程退出
                close(p[0]);
                exit(0);
            }
            else if (pid > 0)
            {
                // 父进程关闭读端
                close(p[0]);
                // 描述子进程信息
                const std::string name = "process_" + std::to_string(i);
                // std::cout<< "90:" << p[1] <<std::endl;
                ProcessDate proc(name, pid, p[1]);
                // 组织子进程信息
                _vectors.push_back(proc);
            }
        }
    }

    void wait()
    {
        for (auto &proc : _vectors)
        {
            // 关闭写端，读段就会读到0，做判断，让子进程退出
            close(proc.Fd());
            pid_t pid = waitpid(proc.Pid(), nullptr, 0);
            if (pid > 0)
            {
                std::cout << "pid:" << pid << ", wait success" << std::endl;
            }
        }
    }

    void push(int taskId)
    {
        // rr轮转的方式，指派子进程任务
        static size_t index = 0;
        int fd = _vectors[index].Fd();

        // 发送任务
        write(fd,&taskId,4);

        index = (index + 1) % _vectors.size();
    }

    void addTask(const task_t s)
    {
        task.addTask(s);
    }

    int taksCount()
    {
        return task.taskCount();
    }

private:
    std::vector<ProcessDate> _vectors;
    int procNum;
    Task task;
};